#include "newGridAction.h"



//Constructor
newGridAction::newGridAction(viewer* v)
: explanation("Create a new grid:"),
widthL("Grid side (>=10 and <=100)"),
expAlignment(Gtk::ALIGN_LEFT, Gtk::ALIGN_TOP, 0, 0),
tableAlignment(Gtk::ALIGN_LEFT, Gtk::ALIGN_TOP, 0, 0),
buttonAlignment(Gtk::ALIGN_RIGHT, Gtk::ALIGN_BOTTOM, 0.15, 0),
v(v)
{
	//Get the default VBox of the dialog and add to it our vertical box
	Gtk::VBox * box = newDialog.get_vbox();
	box->pack_start(vbox);

	//Pack the elements of the dialog (a label, a table and a button) in the vbox
	vbox.pack_start(expAlignment);
	vbox.pack_start(tableAlignment);
	vbox.pack_start(buttonAlignment);
	expAlignment.add(explanation);
	tableAlignment.add(t);
	buttonAlignment.add(button);

	//Arrange the labels and entries in the table
	t.attach(widthL, 0, 1, 0, 1);
	t.attach(widthE, 1, 2, 0, 1);

	//Set some attributes of the widgets
	button.set_label("OK");
	t.set_row_spacings(4);
	t.set_col_spacings(4);
	widthE.set_max_length(3);
	widthE.set_width_chars(11);
	expAlignment.set_border_width(3);
	tableAlignment.set_border_width(3);
	buttonAlignment.set_border_width(3);
	newDialog.set_resizable(false);

	//When the OK button is clicked, the function on_create_grid_button_clicked is called
	button.signal_clicked().connect(sigc::mem_fun(*this, &newGridAction::on_create_grid_button_clicked));

	//Show every widget
	box->show_all_children();

	//Create the newGridData object
	gData = new gridData();
	gData->width = 0;
	gData->pmap = 0;
	gData->pcells = 0;
	gData->pcalls = 0;
	gData->grid = 0;
	gData->initialValueCells = 0;
	gData->scrollW = 0;
	gData->cellSpacing = false;

	//Set the gridData of the modifyGridAction instance to let it execute its operations
	modifyGridAction::setGridData(gData);
}

newGridAction::~newGridAction(){}


//Return the structure that contains the information about the grid
gridData* newGridAction::getGridData()
{
	return gData;
}


//Free memory previously allocated
void newGridAction::freeMemory()
{
	if(gData)
	{
		if(gData->pmap) delete gData->pmap;
		if(gData->pcells) delete gData->pcells;
		if(gData->pcalls) delete gData->pcalls;
		if(gData->grid) delete gData->grid;
		if(gData->initialValueCells) delete gData->initialValueCells;
		gData->~gridData();
	}
}


//Show the new dialog
void newGridAction::showNewDialog()
{
	newDialog.show();
}


//Signal handler activated when the OK button of the New File dialog is clicked
void newGridAction::on_create_grid_button_clicked()
{
	//Obtain the width and height parameters and check its correctness
	//If they are not correct, show an error message
	int width = atoi(widthE.get_text().c_str());
	if(width < 10 || width > 100)
	{
		Gtk::MessageDialog dialog(*v, "The side of the grid is not correct", false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_OK, false);
		dialog.set_secondary_text("The side of the grid should be an integer number between 10 and 100.");
		dialog.run();
		return;
	}

	//Store the new value of width
	gData->width = width;

	//Hide the new dialog
	newDialog.hide();

	//If it is not the first time that a new grid is created, the previous grid is removed
	if(gData->pmap != 0)
	{	
		//Free memory
		gData->grid->~Table();
		delete gData->pcalls;
		delete gData->pmap;
		delete gData->pcells;
	}

	//Obtain screen resolution and decide cell size
	Glib::RefPtr<Gdk::Screen> screen = Gdk::Screen::get_default();
	int resX = screen->get_width();
	int resY = screen->get_height();
	gData->height = gData->width * (resY-90) / (resX - 180); 
	int cellSize = (resX - 180) / width;
	if(cellSize >= 100) cellSize = 100;
	else if(cellSize >= 90) cellSize = 90;
	else if(cellSize >= 80) cellSize = 80;
	else if(cellSize >= 70) cellSize = 70;
	else if(cellSize >= 60) cellSize = 60;
	else if(cellSize >= 50) cellSize = 50;
	else if(cellSize >= 40) cellSize = 40;
	else if(cellSize >= 30) cellSize = 30;
	else if(cellSize >= 25) cellSize = 25;
	else if(cellSize >= 20) cellSize = 20;
	else if(cellSize >= 15) cellSize = 15;
	else if(cellSize >= 10) cellSize = 10;
	else if(cellSize >= 5) cellSize = 5;

	std::stringstream out;
	out << cellSize;

	Gdk::Geometry g;
	g.max_height = cellSize*gData->height + 35;
	g.min_height = cellSize*gData->height + 35;
	g.max_width = cellSize*gData->width + 170;
	g.min_width = cellSize*gData->width + 170;
	v->set_geometry_hints(*v, g, (Gdk::HINT_MIN_SIZE | Gdk::HINT_MAX_SIZE));

	gData->ROAD_IMAGE = ("../img/img" + out.str() + "/road.png");
	gData->GRASS_IMAGE = ("../img/img" + out.str() + "/grass.png");
	gData->TRAIL_IMAGE = ("../img/img" + out.str() + "/trail.png");
	gData->WALL_IMAGE = ("../img/img" + out.str() + "/wall.png");
	gData->START_IMAGE = ("../img/img" + out.str() + "/start.png");
	gData->GOAL_IMAGE = ("../img/img" + out.str() + "/goal.png");

	gData->HPATH1_IMAGE = ("../img/img" + out.str() + "/HPath1.png");
	gData->VPATH1_IMAGE = ("../img/img" + out.str() + "/VPath1.png");
	gData->LUPATH1_IMAGE = ("../img/img" + out.str() + "/LUPath1.png");
	gData->LDPATH1_IMAGE = ("../img/img" + out.str() + "/LDPath1.png");
	gData->RUPATH1_IMAGE = ("../img/img" + out.str() + "/RUPath1.png");
	gData->RDPATH1_IMAGE = ("../img/img" + out.str() + "/RDPath1.png");

	gData->HPATH2_IMAGE = ("../img/img" + out.str() + "/HPath2.png");
	gData->VPATH2_IMAGE = ("../img/img" + out.str() + "/VPath2.png");
	gData->LUPATH2_IMAGE = ("../img/img" + out.str() + "/LUPath2.png");
	gData->LDPATH2_IMAGE = ("../img/img" + out.str() + "/LDPath2.png");
	gData->RUPATH2_IMAGE = ("../img/img" + out.str() + "/RUPath2.png");
	gData->RDPATH2_IMAGE = ("../img/img" + out.str() + "/RDPath2.png");

	gData->HPATH1_GRASS_IMAGE = ("../img/img" + out.str() + "/HPath1_grass.png");
	gData->VPATH1_GRASS_IMAGE = ("../img/img" + out.str() + "/VPath1_grass.png");
	gData->LUPATH1_GRASS_IMAGE = ("../img/img" + out.str() + "/LUPath1_grass.png");
	gData->LDPATH1_GRASS_IMAGE = ("../img/img" + out.str() + "/LDPath1_grass.png");
	gData->RUPATH1_GRASS_IMAGE = ("../img/img" + out.str() + "/RUPath1_grass.png");
	gData->RDPATH1_GRASS_IMAGE = ("../img/img" + out.str() + "/RDPath1_grass.png");

	gData->HPATH2_GRASS_IMAGE = ("../img/img" + out.str() + "/HPath2_grass.png");
	gData->VPATH2_GRASS_IMAGE = ("../img/img" + out.str() + "/VPath2_grass.png");
	gData->LUPATH2_GRASS_IMAGE = ("../img/img" + out.str() + "/LUPath2_grass.png");
	gData->LDPATH2_GRASS_IMAGE = ("../img/img" + out.str() + "/LDPath2_grass.png");
	gData->RUPATH2_GRASS_IMAGE = ("../img/img" + out.str() + "/RUPath2_grass.png");
	gData->RDPATH2_GRASS_IMAGE = ("../img/img" + out.str() + "/RDPath2_grass.png");

	gData->HPATH1_TRAIL_IMAGE = ("../img/img" + out.str() + "/HPath1_trail.png");
	gData->VPATH1_TRAIL_IMAGE = ("../img/img" + out.str() + "/VPath1_trail.png");
	gData->LUPATH1_TRAIL_IMAGE = ("../img/img" + out.str() + "/LUPath1_trail.png");
	gData->LDPATH1_TRAIL_IMAGE = ("../img/img" + out.str() + "/LDPath1_trail.png");
	gData->RUPATH1_TRAIL_IMAGE = ("../img/img" + out.str() + "/RUPath1_trail.png");
	gData->RDPATH1_TRAIL_IMAGE = ("../img/img" + out.str() + "/RDPath1_trail.png");

	gData->HPATH2_TRAIL_IMAGE = ("../img/img" + out.str() + "/HPath2_trail.png");
	gData->VPATH2_TRAIL_IMAGE = ("../img/img" + out.str() + "/VPath2_trail.png");
	gData->LUPATH2_TRAIL_IMAGE = ("../img/img" + out.str() + "/LUPath2_trail.png");
	gData->LDPATH2_TRAIL_IMAGE = ("../img/img" + out.str() + "/LDPath2_trail.png");
	gData->RUPATH2_TRAIL_IMAGE = ("../img/img" + out.str() + "/RUPath2_trail.png");
	gData->RDPATH2_TRAIL_IMAGE = ("../img/img" + out.str() + "/RDPath2_trail.png");

	//Create the new grid
	gData->grid = manage(new Gtk::Table(gData->width, gData->height, false));

	//Set the spacings of the grid
	if(gData->cellSpacing)
	{
		gData->grid->set_row_spacings(1);
		gData->grid->set_col_spacings(1);
	}
	else
	{
		gData->grid->set_row_spacings(0);
		gData->grid->set_col_spacings(0);
	}

	//Add the grid to the scrolled window
	gData->scrollW->add(*(gData->grid));
	gData->scrollW->show_all_children();

	//Unset the start and goal coordinates
	gData->startX = -1;
	gData->startY = -1;
	gData->goalX = -1;
	gData->goalY = -1;

	//Allocate memory for the array of cells that will store the color of each cell
	gData->pmap = new int[gData->width*gData->height];

	//Allocate memory for the array of pointers to Event boxes that will store the box of each cell
	gData->pcells = new Gtk::EventBox*[gData->width*gData->height];

	//Allocate memory for the array of pointers to Event boxes that will store the box of each cell
	gData->pcalls = new bool[gData->width*gData->height];

	//If there has been a problem allocating memory, show the error message
	if (gData->pmap == 0)
	{
		Gtk::MessageDialog dialog(*v, "Memory could not be allocated", false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_OK, false);
		dialog.run();
		return;
	}
	if (gData->pcells == 0)
	{
		Gtk::MessageDialog dialog(*v, "Memory could not be allocated", false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_OK, false);
		dialog.run();
		return;
	}
	if (gData->pcalls == 0)
	{
		Gtk::MessageDialog dialog(*v, "Memory could not be allocated", false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_OK, false);
		dialog.run();
		return;
	}

	//Create a grid of event boxes on the table
	for(int y = 0; y < gData->height; y++)
	{
		for(int x = 0; x < gData->width; x++)
		{
			//Initialise the array of cells to ROAD_CELL
			*(gData->pmap + y*gData->width + x) = Pfv::ROAD_CELL;

			//Initialise the array of firstCall to true
			*(gData->pcalls + y*gData->width + x) = true;

			//Create the event box and the label
			Gtk::EventBox* eb = manage(new Gtk::EventBox());
			*(gData->pcells + y*gData->width + x) = eb;
			eb->set_size_request(cellSize, cellSize);
			
			//Add the event box to the grid
			gData->grid->attach(*eb, x, x + 1, y, y + 1);

			//Set the image of the event box to ROAD_IMAGE
			eb->modify_bg_pixmap(Gtk::STATE_NORMAL, gData->ROAD_IMAGE);

  			//When an event box is clicked, the method on_button_press_event will be executed
			//A pointer to the event box and its coordinates in the grid will be passed as arguments
			eb->signal_button_press_event().connect(sigc::bind<int, int>(sigc::mem_fun(*this,
              						&newGridAction::on_cell_clicked), x, y));
			eb->signal_size_allocate().connect(sigc::bind<Gtk::EventBox*, int, int>(sigc::mem_fun(*this,
              						&newGridAction::on_grid_image_resized), eb, x, y));

			eb->signal_enter_notify_event().connect(sigc::bind<int, int>(sigc::mem_fun(*this,
									&newGridAction::on_mouse_over_cell), x, y));
		}
	}

	//Show everything in the grid
	gData->grid->show_all_children();
}


//When 
bool newGridAction::on_mouse_over_cell(GdkEventCrossing* event, int x, int y)
{
	modifyGridAction::mouseOverCell(event, x, y, v->getCellButtonActive());
}


//Signal handler activated when a cell of the grid is clicked
bool newGridAction::on_cell_clicked(GdkEventButton* event, int x, int y)
{
	modifyGridAction::cellClicked(event, x, y, v->getCellButtonActive());
}


//Resize the image when the eventbox has been resized
void newGridAction::on_grid_image_resized(Gdk::Rectangle& r, Gtk::EventBox* eb, int x, int y)
{
	modifyGridAction::resizeGridImage(r, eb, x, y);
}
